<template>
	<div class="v-select" @click.stop="toggleMenu" v-clickoutside="handleClose">
		<v-input
			v-model="selectedLabel"
			:placeHolder="placeHolder"
			:readonly="true"
			:disabled="disabled"
			:clearable="clearable"
			ref="input"
		></v-input>
		<i class="v-select_icon" :class="{ up: dropDown }"></i>
		<transition name="fade">
			<span v-show="dropDown" class="v-select-option">
				<slot></slot>
			</span>
		</transition>
	</div>
</template>
<script>
import VInput from "../input/input.vue";
import Emitter from "../../assets/emitter";
import Clickoutside from "@/utils/clickoutside";
import { getValueByPath } from "@/utils/util";
export default {
	name: "VSelect",
	componentName: "VSelect",
	components: {
		VInput,
	},
	mixins: [Emitter],
	provide() {
		return {
			select: this,
		};
	},
	data() {
		return {
			options: [],
			cachedOptions: [],
			dropDown: false,
			selectedLabel: "",
			selected: "",
			createdLabel: "",
			createdSelected: "",
		};
	},
	directives: { Clickoutside },
	props: {
		value: {
			required: true,
		},
		placeHolder: String,
		disabled: Boolean,
		clearable: Boolean,
		valueKey: {
			type: String,
			default: "value",
		}, //作为 value 唯一标识的键名，绑定值为对象类型时必填
	},
	computed: {},
	watch: {
		value() {
			this.setSelected();
		},
	},
	created() {
		this.$on("handleOptionClick", this.handleOptionSelect);
		this.$on("setSelected", this.setSelected);
	},
	mounted() {
		this.setSelected();
	},
	methods: {
		toggleMenu() {
			if (!this.disabled) {
				this.dropDown = !this.dropDown;
				if (this.dropDown) {
					this.$refs.input.focus();
					this.$nextTick().then(() => {
						this.broadcast("VOption", "queryChange", this.value);
					});
				}
			}
		},
		handleOptionSelect(option) {
			this.dropDown = false;
			this.$emit("input", option.value);
			this.$emit("change", option.label);
			this.broadcast("VOption", "queryChange", option.value);
		},
		enter() {
			this.hover = true;
		},
		handleClose() {
			this.dropDown = false;
		},
		setSelected() {
			let option = this.getOption(this.value);
			if (option.created) {
				this.createdLabel = option.currentLabel;
				this.createdSelected = true;
			} else {
				this.createdSelected = false;
			}
			this.selectedLabel = option.currentLabel;
			this.selected = option;
		},
		getOption(value) {
			let option;
			const isObject =
				Object.prototype.toString.call(value).toLowerCase() ===
				"[object object]";
			const isNull =
				Object.prototype.toString.call(value).toLowerCase() === "[object null]";
			const isUndefined =
				Object.prototype.toString.call(value).toLowerCase() ===
				"[object undefined]";

			for (let i = this.cachedOptions.length - 1; i >= 0; i--) {
				const cachedOption = this.cachedOptions[i];
				const isEqual = isObject
					? getValueByPath(cachedOption.value, this.valueKey) ===
					  getValueByPath(value, this.valueKey)
					: cachedOption.value === value;
				if (isEqual) {
					option = cachedOption;
					break;
				}
			}
			if (option) return option;
			const label = !isObject && !isNull && !isUndefined ? value : "";
			let newOption = {
				value: value,
				currentLabel: label,
			};
			return newOption;
		},
	},
};
</script>
<style lang="less" scoped>
.fade-enter-active,
.fade-leave-active {
	opacity: 1;
	transform: scaleY(1);
	transition: transform 300ms cubic-bezier(0.23, 1, 0.32, 1),
		opacity 300ms cubic-bezier(0.23, 1, 0.32, 1);
	transform-origin: center top;
}
.fade-enter,
.fade-leave-active {
	opacity: 0;
	transform: scaleY(0);
}
</style>
